import xml.dom.minidom as xml

def attr2string(attr):
	base = ''
	for k in attr:
		base += "%s=\"%s\" "%(str(k), str(attr[k]))
	return base.strip()

def member2node(key, val):
	if not isinstance(key, str):
		raise TypeError, "key must be a string"
	if not val:
		return "<%s />"%key
	if isinstance(val, (str,unicode)):
		return "<%s>%s</%s>"%(key, val, key)
	if isinstance(val, tuple):
		if isinstance(val[0], str):
			return "<%s %s>%s</%s>"%(key, attr2string(val[1]), val[0], key)
		elif isinstance(val[0], dict):
			return "<%s %s>%s</%s>"%(key, attr2string(val[1]), dict2xml(val[0], False), key)
	if isinstance(val, dict):
		return dict2xml(val, key)
	raise TypeError, "val must be a string or a tuple or a dict"


def dict2xml(dic, root = "my_xml"):
	"""
	dic argument must look like so:
	{"hello" : (str(value), {attr})}
	or:
	{"hello" : str(value)}
	or:
	{"hello" : {xml dict}}
	attr must be a full string dict

	will also work for list of tuples for recurring strings
	"""
	base = ''
	if isinstance(dic, dict):
		for k in dic:
			base += member2node(k, dic[k])
	elif isinstance(dic, list):
		for i in dic:
			if isinstance(i, tuple) and len(i) == 2:
				base += member2node(i[0], i[1])
			else:
				raise TypeError, "must be a list of len-2 tuples"
	else:
		raise TypeError, "not a valid dic"
	if not root:
		return base
	return "<%s>%s</%s>"%(root, base, root)

class Ximple(object):
	def __init__(self, base):
		if isinstance(base, str):
			self.base = xml.parseString(base)
		elif isinstance(base, dict):
			self.base = xml.parseString(dict2xml(base))
		else:
			raise TypeError, "Ximple can only parse a string or a dictionary object"
		self.base = self.base.childNodes[0]
		self.tag = self.base.tagName
		self.children = []
		self.text = ''
		for node in self.base.childNodes:
			if node.nodeType != node.TEXT_NODE:
				self.children.append(Ximple(str(node.toxml())))
			else:
				self.text += node.nodeValue

	def __repr__(self):
		return "<Ximple object of root '%s'>"%self.tag

	def __str__(self):
		return str(self.base.toxml())

	def __len__(self):
		return len(self.children)

	def __iter__(self):
		return iter(self.children)

	def __getitem__(self, item):
		if not isinstance(item, slice):
			return Ximple(str(self.base.getElementsByTagName(item)[0].toxml()))
		if item.start:
			tag = item.start
			if item.stop:
				attr = item.stop
				return self.base.getElementsByTagName(tag)[0].getAttribute(attr)
			return self[tag]
		elif item.stop:
			attr = item.stop
			return self.base.getAttribute(attr)

	def __setitem__(self, item, val):
		if not isinstance(item, slice):
			self.base.getElementsByTagName(item)[0] = val
		else:
			if item.start:
				tag = item.start
				if item.stop:
					attr = item.stop
					self.base.getElementsByTagName(tag)[0].setAttribute(attr, val)
				self[tag] = val
			elif item.stop:
				attr = item.stop
				self.base.setAttribute(attr, val)

	def __call__(self, item = None):
		if item:
			return [Ximple(str(n.toxml())) for n in self.base.getElementsByTagName(item)]
		return self.children


class RenderedXimple(object):
	def __init__(self, xobject):
		if not isinstance(xobject, Ximple):
			raise TypeError, "must get Ximple object as base"
		for node in xobject:
			self.__setattr__(node.tag, node.text)

	def __repr__(self):
		return "<Rendered Ximple object>"
